Skip to content

KAFKA-20790: Promote streams assignor API to public module#22788

Open
gabriellefu wants to merge 16 commits into
apache:trunkfrom
gabriellefu:kip1357
Open

KAFKA-20790: Promote streams assignor API to public module#22788
gabriellefu wants to merge 16 commits into
apache:trunkfrom
gabriellefu:kip1357

Conversation

@gabriellefu

@gabriellefu gabriellefu commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Changes

New public API package

org.apache.kafka.coordinator.group.api.assignor.streams (in group-coordinator-api), all annotated with @InterfaceAudience.Public and @InterfaceStability.Evolving.

  • Moved TaskAssignor, GroupAssignment, GroupSpec, MemberAssignment, MemberSubscription, TaskId, TopologyDescriber, and TaskAssignorException from the internal streams.assignor package into the new public package.
  • Added package-info.java.
  • Reshaped the input/output contracts to match the KIP:
    • GroupSpec now exposes memberIds(), memberSubscription(id), memberAssignmentState(id), and configs() instead of members() and assignmentConfigs().
    • MemberSubscription is now a thin interface containing instanceId, rackId, processId, and clientTags.
    • Introduced MemberAssignmentState with activeTasks, standbyTasks, warmupTasks, taskOffsets, and taskEndOffsets to represent a member’s current assignment state, split out from the previous larger member spec.
    • MemberAssignment is now an interface exposing only activeTasks() and standbyTasks(). Warm-up tasks are no longer produced by the assignor and are now determined during reconciliation.

Internal implementations

These remain in group-coordinator, under the streams.assignor package.

  • Added MemberSubscriptionAndAssignmentImpl, which implements both MemberSubscription and MemberAssignmentState.
  • Added MemberAssignmentImpl, which implements MemberAssignment.
  • Removed the old AssignmentMemberSpec record.
  • Reworked GroupSpecImpl to back the new GroupSpec interface.
  • Updated the built-in assignors (StickyTaskAssignor, MockAssignor) and TargetAssignmentBuilder to use the new interfaces.
  • TargetAssignmentBuilder now always emits empty warm-up tasks in the resulting target assignment.
  • Updated import paths in GroupMetadataManager, TopologyMetadata, MemberTaskOffsets, and ProcessState.

Tests and benchmarks

  • Updated the streams assignor tests, TargetAssignmentBuilderTest, GroupMetadataManagerTest, and the JMH benchmarks (StreamsAssignorBenchmarkUtils, StreamsStickyAssignorBenchmark) to use the new API.
  • Rewrote GroupSpecImplTest to exercise the new accessors.
  • Restricted the output-asserting parameterized tests (testAssignmentHasNotChanged, testAssignmentSwapped, testPartialAssignmentUpdate) to ACTIVE and STANDBY, since warm-up tasks can no longer appear in assignor output.

Reviewers: Matthias J. Sax matthias@confluent.io

@gabriellefu gabriellefu changed the title KAFKA-20683: Add broker side custom assignors for "streams" groups KAFKA-20790: Add broker side custom assignors for "streams" groups Jul 8, 2026
@gabriellefu gabriellefu changed the title KAFKA-20790: Add broker side custom assignors for "streams" groups KAFKA-20790: Promote streams assignor API to public module Jul 9, 2026

@mjsax mjsax left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made a pass... Curious to hear from others.

*/
@InterfaceAudience.Public
@InterfaceStability.Evolving
public record TaskId(String subtopologyId, int partition) implements Comparable<TaskId> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems KIP-1357 forget to include this one? Should also become an interface for this case, right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can make it into a interface and update my kip accordingly, thanks

/**
* @return The last received cumulative task offsets of assigned tasks or dormant tasks.
*/
Map<TaskId, Long> taskOffsets();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One argument during KIP discussion was, to return data based on wire format. That's why we don't have Set<TaskId> activeTasks() but Map<String, Set<Integer>> activeTasks().

And I just realize that the wire-format between both task-ids (which is an array of []TaskId and each TaskId is String,[]int32 format) and task-offsets (which is an array of []TaskOffset and each TaskOffset is string,int32,int64) have a different format...

But I am now wondering what the best representation for string,int32,int64 triple would be -- while Map<TaskId, Long> (with TaskId == String + int) is not a bad fit, it's somewhat a mismatch to what we do for activeTasks() above... 🤔

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think maybe keep it the Map<TaskId, Long> is more reasonable, I have update the interface of Taskid

*/
@InterfaceAudience.Public
@InterfaceStability.Evolving
public record GroupAssignment(Map<String, MemberAssignment> members) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The KIP defines this as a class, not a record. -- Given that this is an output/return type, not an input to the assignor, it might actually be ok to keep as record, and we could also update the KIP?

\cc @lianetm for input

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I will update my kip and make it into a record.

@github-actions github-actions Bot removed the triage PRs from the community label Jul 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants